// TerrainDialog.cpp : implementation file
//

#include "stdafx.h"
#include "TerrainDialog.h"
#include "DimensionsDialog.h"
#include "CryEditDoc.h"

#include "NumberDlg.h"
#include ".\Terrain\GenerationParam.h"
#include ".\Terrain\Noise.h"

#include "SizeDialog.h"
#include "TerrainLighting.h"
#include "ViewManager.h"

#include "TerrainModifyTool.h"
#include "TerrainModifyPanel.h"
#include "VegetationMap.h"

#include "Terrain/Heightmap.h"
#include "Terrain/TerrainManager.h"

#include "GameEngine.h"
#include "SegmentedWorld/SegmentedWorldManager.h"

#define IDW_ROLLUP_PANE      AFX_IDW_CONTROLBAR_FIRST+10

//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CTerrainDialog,CBaseFrameWnd)

//////////////////////////////////////////////////////////////////////////
class CTerrainEditorViewClass : public IViewPaneClass
{
	//////////////////////////////////////////////////////////////////////////
	// IClassDesc
	//////////////////////////////////////////////////////////////////////////
	virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_VIEWPANE; };
	virtual REFGUID ClassID()
	{
		// {CB15B296-6829-459d-BA26-A5C0BFE0B8F5}
		static const GUID guid = { 0xcb15b296, 0x6829, 0x459d, { 0xba, 0x26, 0xa5, 0xc0, 0xbf, 0xe0, 0xb8, 0xf5 } };
		return guid;
	}
	virtual const char* ClassName() { return _T("Terrain Editor"); };
	virtual const char* Category() { return _T("Terrain"); };
	//////////////////////////////////////////////////////////////////////////
	virtual CRuntimeClass* GetRuntimeClass() { return RUNTIME_CLASS(CTerrainDialog); };
	virtual const char* GetPaneTitle() { return _T("Terrain Editor"); };
	virtual EDockingDirection GetDockingDirection() { return DOCK_FLOAT; };
	virtual CRect GetPaneRect() { return CRect(100,100,1000,800); };
	virtual bool SinglePane() { return false; };
	virtual bool WantIdleUpdate() { return true; };
};
REGISTER_CLASS_DESC(CTerrainEditorViewClass)

/////////////////////////////////////////////////////////////////////////////
// CLoadFixedScaleHeightmapDlg dialog
class CLoadFixedScaleHeightmapDlg : public CDialog
{
	DECLARE_DYNAMIC(CLoadFixedScaleHeightmapDlg)

public:
	CLoadFixedScaleHeightmapDlg(CWnd* pParent = NULL);   // standard constructor
	virtual ~CLoadFixedScaleHeightmapDlg();

// Dialog Data
	enum { IDD = IDD_LOAD_TERRAIN_FIXED_SCALE };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

	DECLARE_MESSAGE_MAP()

  virtual BOOL OnInitDialog();

public:
  CString m_sFileName;
  CString m_sScaleLow;
  CString m_sScaleHigh;

  float m_fScaleLow;
  float m_fScaleHigh;

  afx_msg void OnBnClickedOk();
  afx_msg void OnBnClickedBrowse();
};

// Implementation

IMPLEMENT_DYNAMIC(CLoadFixedScaleHeightmapDlg, CDialog)

CLoadFixedScaleHeightmapDlg::CLoadFixedScaleHeightmapDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CLoadFixedScaleHeightmapDlg::IDD, pParent)
  , m_sFileName(_T(""))
  , m_sScaleLow(_T(""))
  , m_sScaleHigh(_T(""))
  , m_fScaleLow(0.0f)
  , m_fScaleHigh(0.0f)
{

}

CLoadFixedScaleHeightmapDlg::~CLoadFixedScaleHeightmapDlg()
{
}

void CLoadFixedScaleHeightmapDlg::DoDataExchange(CDataExchange* pDX)
{
  CDialog::DoDataExchange(pDX);
  DDX_Text(pDX, IDC_EDIT1, m_sFileName);
  DDX_Text(pDX, IDC_EDIT3, m_sScaleLow);
  DDX_Text(pDX, IDC_EDIT2, m_sScaleHigh);
}

BEGIN_MESSAGE_MAP(CLoadFixedScaleHeightmapDlg, CDialog)
  ON_BN_CLICKED(IDOK, &CLoadFixedScaleHeightmapDlg::OnBnClickedOk)
  ON_BN_CLICKED(IDC_BUTTON1, &CLoadFixedScaleHeightmapDlg::OnBnClickedBrowse)
END_MESSAGE_MAP()

BOOL CLoadFixedScaleHeightmapDlg::OnInitDialog()
{
  m_sScaleLow = _T("0");
  m_sScaleHigh = _T("4096");
  UpdateData(false);
  return TRUE;
}

void CLoadFixedScaleHeightmapDlg::OnBnClickedOk()
{
  UpdateData();

  m_fScaleLow = (float) _tstof(m_sScaleLow.GetBuffer());
  m_fScaleHigh = (float) _tstof(m_sScaleHigh.GetBuffer());

  if (m_fScaleLow >= m_fScaleHigh) {
    MessageBox(_T("Invalid scale values"), _T("Input error"), MB_ICONERROR);
    return;
  }

  CFile heightmapFile;
  CFileException err;

  if (!heightmapFile.Open(m_sFileName.GetBuffer(), CFile::modeRead, &err)) {
    char buf[256];
    err.GetErrorMessage(buf, 256);
    CString sError = CString("Cannot open the heightmap file: ") + CString(buf);
    MessageBox(sError.GetBuffer(), "File error", MB_ICONERROR);
    return;
  }

  heightmapFile.Close();
  OnOK();
}

void CLoadFixedScaleHeightmapDlg::OnBnClickedBrowse()
{
  UpdateData();
  const char *pcFilters = "All Images Files|*.pgm;*.raw;*.r16|16-bit PGM Files (*.pgm)|*.pgm|16-bit RAW Files (*.raw, *.r16)|*.raw;*.r16|All files (*.*)|*.*||";
	CFileDialog fileDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR, (const char*) pcFilters);
  
  if (fileDialog.DoModal() == IDOK) {
    m_sFileName = fileDialog.GetPathName();
    UpdateData(FALSE);
  }
}

/////////////////////////////////////////////////////////////////////////////
// CTerrainDialog dialog
CTerrainDialog::CTerrainDialog()
{
	// We don't have valid recent terrain generation parameters yet
	m_sLastParam = new SNoiseParams;
	m_sLastParam->bValid = false;
	m_pViewport = 0;

	m_pHeightmap = GetIEditor()->GetHeightmap();

	CRect rc(0,0,0,0);
	Create( WS_CHILD|WS_VISIBLE,rc,AfxGetMainWnd() );

	GetIEditor()->RegisterNotifyListener(this);
}

CTerrainDialog::~CTerrainDialog()
{
	GetIEditor()->UnregisterNotifyListener(this);
	GetIEditor()->SetEditTool( 0 );
	delete m_sLastParam;
}

BEGIN_MESSAGE_MAP(CTerrainDialog, CBaseFrameWnd)
	ON_MESSAGE(WM_KICKIDLE,OnKickIdle)
	ON_COMMAND(ID_TERRAIN_LOAD, OnTerrainLoad)
  	ON_COMMAND(ID_TERRAIN_LOAD_FIXED_SCALE, OnTerrainLoadFixedScale)
	ON_COMMAND(ID_TERRAIN_ERASE, OnTerrainErase)
	ON_COMMAND(ID_BRUSH_1, OnBrush1)
	ON_COMMAND(ID_BRUSH_2, OnBrush2)
	ON_COMMAND(ID_BRUSH_3, OnBrush3)
	ON_COMMAND(ID_BRUSH_4, OnBrush4)
	ON_COMMAND(ID_BRUSH_5, OnBrush5)
	ON_COMMAND(ID_TERRAIN_RESIZE, OnTerrainResize)
	ON_COMMAND(ID_TERRAIN_LIGHT, OnTerrainLight)
	ON_COMMAND(ID_TERRAIN_SURFACE, OnTerrainSurface)
	ON_COMMAND(ID_TERRAIN_GENERATE, OnTerrainGenerate)
	ON_COMMAND(ID_TERRAIN_INVERT, OnTerrainInvert)
	ON_COMMAND(ID_FILE_EXPORTHEIGHTMAP, OnExportHeightmap)
	ON_COMMAND(ID_MODIFY_MAKEISLE, OnModifyMakeisle)
	ON_COMMAND(ID_MODIFY_FLATTEN_LIGHT, OnModifyFlattenLight)
	ON_COMMAND(ID_MODIFY_FLATTEN_HEAVY, OnModifyFlattenHeavy)
	ON_COMMAND(ID_MODIFY_SMOOTH, OnModifySmooth)
	ON_COMMAND(ID_MODIFY_REMOVEWATER, OnModifyRemovewater)
	ON_COMMAND(ID_MODIFY_SMOOTHSLOPE, OnModifySmoothSlope)
	ON_COMMAND(ID_HEIGHTMAP_SHOWLARGEPREVIEW, OnHeightmapShowLargePreview)
	ON_COMMAND(ID_MODIFY_SMOOTHBEACHESCOAST, OnModifySmoothBeachesOrCoast)
	ON_COMMAND(ID_MODIFY_NOISE, OnModifyNoise)
	ON_COMMAND(ID_MODIFY_NORMALIZE, OnModifyNormalize)
	ON_COMMAND(ID_MODIFY_REDUCERANGE, OnModifyReduceRange)
	ON_COMMAND(ID_MODIFY_REDUCERANGELIGHT, OnModifyReduceRangeLight)
	ON_COMMAND(ID_MODIFY_RANDOMIZE, OnModifyRandomize)
	ON_COMMAND(ID_LOW_OPACITY, OnLowOpacity)
	ON_COMMAND(ID_MEDIUM_OPACITY, OnMediumOpacity)
	ON_COMMAND(ID_HIGH_OPACITY, OnHighOpacity)
	ON_WM_MOUSEWHEEL()
	ON_COMMAND(ID_OPTIONS_SHOWMAPOBJECTS, OnOptionsShowMapObjects)
	ON_COMMAND(ID_OPTIONS_SHOWWATER, OnOptionsShowWater)
	ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWWATER,OnShowWaterUpdateUI)
	ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWMAPOBJECTS,OnShowMapObjectsUpdateUI)
	ON_COMMAND(ID_OPTIONS_EDITTERRAINCURVE, OnOptionsEditTerrainCurve)
	ON_COMMAND(ID_SETWATERLEVEL, OnSetWaterLevel)
	ON_COMMAND(ID_MODIFY_SETMAXHEIGHT, OnSetMaxHeight)
	ON_COMMAND(ID_MODIFY_SETUNITSIZE, OnSetUnitSize)
	ON_COMMAND(ID_TOOLS_CUSTOMIZEKEYBOARD, OnCustomize)
	ON_COMMAND(ID_TOOLS_EXPORT_SHORTCUTS, OnExportShortcuts)
	ON_COMMAND(ID_TOOLS_IMPORT_SHORTCUTS, OnImportShortcuts)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTerrainDialog message handlers

BOOL CTerrainDialog::OnInitDialog() 
{
	CMFCUtils::LoadShortcuts(GetCommandBars(), IDR_TERRAIN, "TerrainEditor");

	// Create and setup the heightmap edit viewport and the toolbars
	GetCommandBars()->GetCommandBarsOptions()->bShowExpandButtonAlways = FALSE;
	GetCommandBars()->EnableCustomization(FALSE);

	CRect rcClient;
	GetClientRect(rcClient);

	CXTPCommandBar* pMenuBar = GetCommandBars()->SetMenu( _T("Menu Bar"),IDR_TERRAIN );	
	pMenuBar->SetFlags(xtpFlagStretched);
	pMenuBar->EnableCustomization(TRUE);

	// Create Library toolbar.
	CXTPToolBar *pToolBar1 = GetCommandBars()->Add( _T("ToolBar1"),xtpBarTop );
	pToolBar1->EnableCustomization(FALSE);
	VERIFY(pToolBar1->LoadToolBar( IDR_TERRAIN ));

	CXTPToolBar *pToolBar2 = GetCommandBars()->Add( _T("ToolBar2"),xtpBarTop );
	pToolBar2->EnableCustomization(FALSE);
	VERIFY(pToolBar2->LoadToolBar( IDR_BRUSHES ));

	DockRightOf(pToolBar2,pToolBar1);

	// Create the status bar.
	{
		UINT indicators[] =
		{
			ID_SEPARATOR,           // status line indicator
		};
		VERIFY( m_wndStatusBar.Create( this, WS_CHILD|WS_VISIBLE|CBRS_BOTTOM) );
		VERIFY( m_wndStatusBar.SetIndicators( indicators,sizeof(indicators)/sizeof(UINT) ) );
	}


	/////////////////////////////////////////////////////////////////////////
	// Docking Pane for TaskPanel
	m_pDockPane_Rollup = GetDockingPaneManager()->CreatePane( IDW_ROLLUP_PANE, CRect(0,0,300,500), dockRightOf );
	//m_pDockPane_Rollup->SetOptions(xtpPaneNoCloseable|xtpPaneNoFloatable);


	m_rollupCtrl.Create( WS_CHILD|WS_VISIBLE,CRect(0,0,100,100),this,2 );

	m_pViewport = new CTopRendererWnd;
	m_pViewport->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
	m_pViewport->MoveWindow( CRect(20,50,500,500) );
	m_pViewport->ModifyStyle( WS_POPUP,WS_CHILD,0 );
	m_pViewport->SetParent( this );
	m_pViewport->SetOwner( this );
	m_pViewport->m_bShowHeightmap = true;
	m_pViewport->ShowWindow( SW_SHOW );
	m_pViewport->SetShowWater( true );
	m_pViewport->SetShowViewMarker( false );

	m_pTerainTool = new CTerrainModifyTool;
	CTerrainModifyPanel *pToolPanel = new CTerrainModifyPanel(m_pTerainTool,&m_rollupCtrl);
	m_pTerainTool->SetExternalUIPanel( pToolPanel );

	m_pViewport->SetEditTool( m_pTerainTool,true );
	GetIEditor()->SetEditTool( m_pTerainTool );

	CTerrainBrush br;
	m_pTerainTool->GetCurBrushParams(br);
	br.height = 100;
	br.radiusInside = 10;
	br.radius = 10;
	m_pTerainTool->SetCurBrushParams(br);

	m_rollupCtrl.InsertPage( "Terrain Brush",pToolPanel );

	//////////////////////////////////////////////////////////////////////////
	char szCaption[128];
	sprintf(szCaption, "Heightmap %ix%i",	m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight());
	m_wndStatusBar.SetPaneText(0, szCaption);

	AutoLoadFrameLayout( "TerrainEditor" );

	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

//////////////////////////////////////////////////////////////////////////
LRESULT CTerrainDialog::OnDockingPaneNotify(WPARAM wParam, LPARAM lParam)
{
	if (wParam == XTP_DPN_SHOWWINDOW)
	{
		// get a pointer to the docking pane being shown.
		CXTPDockingPane* pwndDockWindow = (CXTPDockingPane*)lParam;    
		if (!pwndDockWindow->IsValid())
		{
			switch (pwndDockWindow->GetID())
			{
			case IDW_ROLLUP_PANE:
				pwndDockWindow->SetOptions(xtpPaneNoCloseable);
				pwndDockWindow->Attach(&m_rollupCtrl);
				break;
			default:
				return FALSE;
			}
		}
		return TRUE;
	}
	else if (wParam == XTP_DPN_CLOSEPANE)
	{
		// get a pointer to the docking pane being closed.
		CXTPDockingPane* pwndDockWindow = (CXTPDockingPane*)lParam;
		if (pwndDockWindow->IsValid())
		{
		}
	}

	return FALSE;
}

//////////////////////////////////////////////////////////////////////////
CTerrainModifyTool* CTerrainDialog::GetTerrainTool()
{
	return m_pTerainTool;
}

//////////////////////////////////////////////////////////////////////////
LRESULT CTerrainDialog::OnKickIdle(WPARAM wParam, LPARAM lParam)
{
	if (m_pViewport)
		m_pViewport->Update();
	
	return FALSE;
}

void CTerrainDialog::OnTerrainLoadFixedScale() 
{
  CLoadFixedScaleHeightmapDlg dlg;

	if (dlg.DoModal() != IDOK)
    return;

	//SW pre-change detection
	SW_TEST_TERRAIN_MOD(0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);

	char ext[_MAX_EXT];
  _splitpath(dlg.m_sFileName, NULL, NULL, NULL, ext);
	CWaitCursor wait;

	if (stricmp(ext, ".pgm") == 0)
		m_pHeightmap->LoadPGM(dlg.m_sFileName, dlg.m_fScaleLow, dlg.m_fScaleHigh);
	else if (stricmp(ext, ".raw") == 0 || stricmp(ext, ".r16") == 0)
		m_pHeightmap->LoadRAW(dlg.m_sFileName, dlg.m_fScaleLow, dlg.m_fScaleHigh);
  else {
    MessageBox(_T("Invalid file - only .raw and .pgm files are supported!"), _T("Input error"), MB_ICONERROR);
    return;
  }

	InvalidateTerrain();

	//SW notification callback
	AABB swBox;
	CSWManager::CoordToAABB(swBox, 0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);
	SW_ON_HMAP_MOD(swBox);
}

void CTerrainDialog::OnTerrainLoad() 
{
	////////////////////////////////////////////////////////////////////////
	// Load a heightmap from a file
	////////////////////////////////////////////////////////////////////////
	
	char szFilters[] = "All Images Files|*.bmp;*.pgm;*.raw;*.r16|8-bit Bitmap Files (*.bmp)|*.bmp|16-bit PGM Files (*.pgm)|*.pgm|16-bit RAW Files (*.raw, *.r16)|*.raw;*.r16|All files (*.*)|*.*||";
	CAutoDirectoryRestoreFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR, szFilters);

	if (dlg.DoModal() == IDOK) 
	{
		SW_TEST_TERRAIN_MOD(0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);

		char ext[_MAX_EXT];
		_splitpath( dlg.GetPathName(),NULL,NULL,NULL,ext );
		
		CWaitCursor wait;

		if (stricmp(ext,".pgm") == 0)
		{
			m_pHeightmap->LoadPGM( dlg.GetPathName() );
		}
		else if (stricmp(ext,".raw") == 0 || stricmp(ext,".r16") == 0)
		{
			m_pHeightmap->LoadRAW( dlg.GetPathName() );
		}
		else
		{
			// Load the heightmap
			m_pHeightmap->LoadBMP(dlg.GetPathName());
		}

		InvalidateTerrain();

		if (m_pViewport)
			m_pViewport->InitHeightmapAlignment();
		InvalidateViewport();

		//SW notification callback
		AABB swBox;
		CSWManager::CoordToAABB(swBox, 0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);
		SW_ON_HMAP_MOD(swBox);
	}
}

void CTerrainDialog::OnTerrainErase() 
{
	////////////////////////////////////////////////////////////////////////
	// Erase the heightmap
	////////////////////////////////////////////////////////////////////////

	// Ask first
	if (AfxMessageBox("Really erase the heightmap ?", MB_ICONQUESTION | MB_YESNO, NULL) != IDYES)
		return;

	SW_TEST_TERRAIN_MOD(0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);

	// Erase it
	m_pHeightmap->Clear();

	InvalidateTerrain();

	// All layers need to be generated from scratch
	CTerrainManager::GetTerrainManager().InvalidateLayers();

	//SW notification callback
	AABB swBox;
	CSWManager::CoordToAABB(swBox, 0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);
	SW_ON_HMAP_MOD(swBox);
}

void CTerrainDialog::OnTerrainResize() 
{
	((CCryEditApp*)AfxGetApp())->OnTerrainResizeterrain();
}

void CTerrainDialog::OnTerrainInvert() 
{
	////////////////////////////////////////////////////////////////////////
	// Invert the heightmap
	////////////////////////////////////////////////////////////////////////
	
	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;

	m_pHeightmap->Invert();

	InvalidateTerrain();
}

void CTerrainDialog::OnTerrainGenerate() 
{
	////////////////////////////////////////////////////////////////////////
	// Generate a terrain
	////////////////////////////////////////////////////////////////////////

	SNoiseParams sParam;
	CGenerationParam cDialog;
	
	if (GetLastParam()->bValid)
	{
		// Use last parameters
		cDialog.LoadParam(GetLastParam());
	}
	else
	{
		// Set default parameters for the dialog
		cDialog.m_sldFrequency = (int) (7.0f * 10);  // Feature Size
		cDialog.m_sldFade = (int) (0.46f * 10);  // Bumpiness
		cDialog.m_sldPasses = 8;  // Detail (Passes)
		cDialog.m_sldRandomBase = 1;  // Variation
		cDialog.m_sldBlur = 0;
		cDialog.m_sldCover = 0;
		cDialog.m_sldSharpness = (int) (0.999f * 1000);
		cDialog.m_sldFrequencyStep = (int) (2.0f * 10);
	}
				
	// Show the generation parameter dialog
	if (cDialog.DoModal() == IDCANCEL)
		return;

	SW_TEST_TERRAIN_MOD(0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);
	
	GetIEditor()->FlushUndo();

	CLogFile::WriteLine("Generating new terrain...");

	// Fill the parameter structure for the terrain generation
	cDialog.FillParam(&sParam);
	sParam.iWidth = m_pHeightmap->GetWidth();
	sParam.iHeight = m_pHeightmap->GetHeight();
	sParam.bBlueSky = false;

	// Save the paramters
	ZeroStruct( *m_sLastParam );

	CWaitCursor wait;
	// Generate
	m_pHeightmap->GenerateTerrain(sParam);


	//SW notification callback
	AABB swBox;
	CSWManager::CoordToAABB(swBox, 0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);
	SW_ON_HMAP_MOD(swBox);

	InvalidateTerrain();
}

void CTerrainDialog::OnExportHeightmap()
{
	////////////////////////////////////////////////////////////////////////
	// Export the heightmap to BMP
	////////////////////////////////////////////////////////////////////////

	char szFilters[] = "8-bit Bitmap (*.bmp)|*.bmp|16-bit PGM (*.pgm)|*.pgm|16-bit RAW (*.raw)|*.raw||";
	CAutoDirectoryRestoreFileDialog dlg(FALSE, "bmp", NULL, OFN_OVERWRITEPROMPT|OFN_NOCHANGEDIR, szFilters);
	
	// Show the dialog
	if (dlg.DoModal() == IDOK) 
	{
		BeginWaitCursor();

		CLogFile::WriteLine("Exporting heightmap...");


		char ext[_MAX_EXT];
		_splitpath( dlg.GetPathName(),NULL,NULL,NULL,ext );
		if (stricmp(ext,".pgm") == 0)
		{
			// PGM
			m_pHeightmap->SavePGM( dlg.GetPathName() );
		}
		else if (stricmp(ext,".raw") == 0)
		{
			// PGM
			m_pHeightmap->SaveRAW( dlg.GetPathName() );
		}
		else
		{
			// BMP or others
			m_pHeightmap->SaveImage( dlg.GetPathName() );
		}
		
		EndWaitCursor();
	}
}

void CTerrainDialog::OnModifySmoothBeachesOrCoast() 
{
	////////////////////////////////////////////////////////////////////////
	// Make smooth beaches or a smooth coast
	////////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;

	// Call the smooth beaches function of the heightmap class
	m_pHeightmap->MakeBeaches();
	InvalidateTerrain();
}

void CTerrainDialog::OnModifyMakeisle() 
{
	SW_TEST_TERRAIN_MOD(0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);

	////////////////////////////////////////////////////////////////////////
	// Convert the heightmap to an island
	////////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;

	// Call the make isle fucntion of the heightmap class
	m_pHeightmap->MakeIsle();

	//SW notification callback
	AABB swBox;
	CSWManager::CoordToAABB(swBox, 0, 0, m_pHeightmap->GetWidth(), m_pHeightmap->GetHeight(), true, false);
	SW_ON_HMAP_MOD(swBox);

	InvalidateTerrain();
}

void CTerrainDialog::Flatten(float fFactor)
{
	////////////////////////////////////////////////////////////////////////
	// Increase the number of flat areas on the heightmap
	////////////////////////////////////////////////////////////////////////

	CWaitCursor wait;

	// Call the flatten function of the heigtmap class
	m_pHeightmap->Flatten(fFactor);

	InvalidateTerrain();
}

void CTerrainDialog::OnModifyFlattenLight() 
{
	if(!GetIEditor()->FlushUndo(true))
		return;

	Flatten(0.75f);
}

void CTerrainDialog::OnModifyFlattenHeavy() 
{
	if(!GetIEditor()->FlushUndo(true))
		return;

	Flatten(0.5f);
}

void CTerrainDialog::OnModifyRemovewater() 
{
	//////////////////////////////////////////////////////////////////////
	// Remove all water areas from the heightmap
	//////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;

	CLogFile::WriteLine("Removing water areas from heightmap...");

	CWaitCursor wait;

	// Using a water level <=0, if we reload the environment, it will
	// cause in method CTerrain::InitTerrainWater the SAFE_DELETE(m_pOcean);
	m_pHeightmap->SetWaterLevel(WATER_LEVEL_UNKNOWN);

	// Changed the InvalidateTerrain to include a environment reload.
	InvalidateTerrain();
}

void CTerrainDialog::OnModifySmoothSlope() 
{
	//////////////////////////////////////////////////////////////////////
	// Remove areas with high slope from the heightmap
	//////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;

	// Call the smooth slope function of the heightmap class
	m_pHeightmap->SmoothSlope();

	InvalidateTerrain();
}

void CTerrainDialog::OnModifySmooth() 
{
	//////////////////////////////////////////////////////////////////////
	// Smooth the heightmap
	//////////////////////////////////////////////////////////////////////

	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;

	m_pHeightmap->Smooth();
	InvalidateTerrain();
}

void CTerrainDialog::OnModifyNoise() 
{
	////////////////////////////////////////////////////////////////////////
	// Noise the heightmap
	////////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;
	
	CWaitCursor wait;
	m_pHeightmap->Noise();
	InvalidateTerrain();
}

void CTerrainDialog::OnModifyNormalize() 
{
	////////////////////////////////////////////////////////////////////////
	// Normalize the heightmap
	////////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;
	
	CWaitCursor wait;
	m_pHeightmap->Normalize();

	InvalidateTerrain();
}

void CTerrainDialog::OnModifyReduceRange() 
{
	////////////////////////////////////////////////////////////////////////
	// Reduce the value range of the heightmap (Heavy)
	////////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;
	m_pHeightmap->LowerRange(0.8f);

	InvalidateTerrain();
}

void CTerrainDialog::OnModifyReduceRangeLight() 
{
	////////////////////////////////////////////////////////////////////////
	// Reduce the value range of the heightmap (Light)
	////////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;
	m_pHeightmap->LowerRange(0.95f);

	InvalidateTerrain();
}

void CTerrainDialog::OnModifyRandomize() 
{
	////////////////////////////////////////////////////////////////////////
	// Add a small amount of random noise
	////////////////////////////////////////////////////////////////////////
	if(!GetIEditor()->FlushUndo(true))
		return;

	CWaitCursor wait;
	m_pHeightmap->Randomize();

	InvalidateTerrain();
}


void CTerrainDialog::OnHeightmapShowLargePreview() 
{
	////////////////////////////////////////////////////////////////////////
	// Show a full-size version of the heightmap
	////////////////////////////////////////////////////////////////////////

	BeginWaitCursor();

	CLogFile::WriteLine("Exporting heightmap...");

	UINT iWidth = m_pHeightmap->GetWidth();
	UINT iHeight = m_pHeightmap->GetHeight();

	float fMaxHeight = m_pHeightmap->GetMaxHeight();

	CImage image;
	image.Allocate( iHeight, iWidth ); // swap x with y
	// Allocate memory to export the heightmap
	DWORD* pImageData = (DWORD*)image.GetData();

	// Get a pointer to the heightmap data
	t_hmap* pHeightmap = m_pHeightmap->GetData();

	// Write heightmap into the image data array
	for (UINT y=0; y < iHeight; ++y)
	{
		for (UINT x=0; x < iWidth; ++x)
		{
			// Get a normalized grayscale value from the heigthmap
			uint8 iColor = (uint8)__min( pHeightmap[x + y * iWidth] / fMaxHeight * 255.0f, 255.0f);

			// Create a BGR grayscale value and store it in the image
			// data array
			pImageData[y + (iWidth-1 - x) * iHeight] =   // swap x with y
				(iColor << 16) | (iColor << 8) | iColor;
		}
	}

	// Save the heightmap into the bitmap
	CString tempDirectory = Path::AddBackslash(gSettings.strStandardTempDirectory);
	CFileUtil::CreateDirectory( tempDirectory.GetBuffer() );

	CString imageName = "HeightmapPreview.bmp";
	bool bOk = CImageUtil::SaveImage( tempDirectory + imageName,image );

	EndWaitCursor();
	
	if (bOk)
	{
		// Show the heightmap
		::ShellExecute(::GetActiveWindow(), "open", imageName.GetBuffer(), 
			"", tempDirectory.GetBuffer(), SW_SHOWMAXIMIZED);
	}
}

BOOL CTerrainDialog::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	////////////////////////////////////////////////////////////////////////
	// Forward mouse wheel messages to the drawing window
	////////////////////////////////////////////////////////////////////////

	return __super::OnMouseWheel(nFlags, zDelta, pt);
}

void CTerrainDialog::OnTerrainLight() 
{
	////////////////////////////////////////////////////////////////////////
	// Show the terrain lighting tool
	////////////////////////////////////////////////////////////////////////
	GetIEditor()->OpenView(LIGHTING_TOOL_WINDOW_NAME);
}

void CTerrainDialog::OnTerrainSurface() 
{
	////////////////////////////////////////////////////////////////////////
	// Show the terrain texture dialog
	////////////////////////////////////////////////////////////////////////

	GetIEditor()->OpenView( "Terrain Texture Layers" );
}

void CTerrainDialog::OnHold()
{
	// Hold the current heightmap state
	m_pHeightmap->Hold();
}

void CTerrainDialog::OnFetch()
{
	int iResult;

	// Did we modify the heigthmap ?
	if (GetIEditor()->IsModified())
	{
		// Ask first
		iResult = MessageBox("Do you really want to restore the previous heightmap state ?", 
			"Fetch", MB_YESNO | MB_ICONQUESTION);

		// Abort
		if (iResult == IDNO)
			return;
	}

	// Restore the old heightmap state
	m_pHeightmap->Fetch();

	// We modified the document
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);

	// All layers need to be generated from scratch
	m_pHeightmap->InvalidateLayers();

	InvalidateTerrain();
}

/////////////////////////////////////////////////////////////////////////////
// Options
void CTerrainDialog::OnShowWaterUpdateUI( CCmdUI* pCmdUI )
{
	pCmdUI->SetCheck( m_pViewport->GetShowWater() ? 1 : 0 );
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::OnShowMapObjectsUpdateUI( CCmdUI* pCmdUI )
{
	pCmdUI->SetCheck( m_pViewport->m_bShowStatObjects ? 1 : 0 );
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::OnOptionsShowMapObjects() 
{
	m_pViewport->m_bShowStatObjects = !m_pViewport->m_bShowStatObjects;

	// Update the draw window
	InvalidateViewport();
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::OnOptionsShowWater() 
{
	m_pViewport->SetShowWater( !m_pViewport->GetShowWater() );
	// Update the draw window
	InvalidateViewport();
}

/////////////////////////////////////////////////////////////////////////////
// Brushes

void CTerrainDialog::OnBrush1() 
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.radiusInside = br.radius = 2;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnBrush2() 
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.radiusInside = br.radius = 10;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnBrush3() 
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.radiusInside = br.radius = 25;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnBrush4() 
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.radiusInside = br.radius = 50;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnBrush5() 
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.radiusInside = br.radius = 100;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnLowOpacity()
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.hardness = 0.2f;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnMediumOpacity()
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.hardness = 0.5f;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnHighOpacity()
{
	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		br.hardness = 1.0;
		GetTerrainTool()->SetCurBrushParams(br);
	}
}

void CTerrainDialog::OnOptionsEditTerrainCurve()
{
}

void CTerrainDialog::OnSetWaterLevel() 
{
	////////////////////////////////////////////////////////////////////////
	// Let the user change the current water level
	////////////////////////////////////////////////////////////////////////
	// Get the water level from the document and set it as default into
	// the dialog
	float fPreviousWaterLevel = GetIEditor()->GetHeightmap()->GetWaterLevel();
	CNumberDlg cDialog( this,fPreviousWaterLevel,"Set Water Height" );

	// Show the dialog
	if (cDialog.DoModal() == IDOK)
	{
		// Retrive the new water level from the dialog and save it in the document
		float waterLevel = cDialog.GetValue();
		GetIEditor()->GetHeightmap()->SetWaterLevel(waterLevel);
		InvalidateTerrain();
	}
}

void CTerrainDialog::OnSetMaxHeight() 
{
	////////////////////////////////////////////////////////////////////////
	// Let the user change the current water level
	////////////////////////////////////////////////////////////////////////
	// Get the water level from the document and set it as default into
	// the dialog
	float fValue = GetIEditor()->GetHeightmap()->GetMaxHeight();
	CNumberDlg cDialog( this,fValue,"Set Max Terrain Height" );

	// Show the dialog
	if (cDialog.DoModal() == IDOK)
	{
		// Retrive the new water level from the dialog and save it in the document
		fValue = cDialog.GetValue();
		GetIEditor()->GetHeightmap()->SetMaxHeight(fValue);

		InvalidateTerrain();
	}
}

void CTerrainDialog::OnSetUnitSize() 
{
	////////////////////////////////////////////////////////////////////////
	// Let the user change the current water level
	////////////////////////////////////////////////////////////////////////
	// Get the water level from the document and set it as default into
	// the dialog
	float fValue = GetIEditor()->GetHeightmap()->GetUnitSize();
	CNumberDlg cDialog( this,fValue,"Set Unit Size (Meters per unit)" );
	cDialog.SetInteger(true);

	// Show the dialog
	if (cDialog.DoModal() == IDOK)
	{
		// Retrive the new water level from the dialog and save it in the document
		fValue = cDialog.GetValue();
		GetIEditor()->GetHeightmap()->SetUnitSize(fValue);

		InvalidateTerrain();
	}
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::InvalidateTerrain()
{
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);
	GetIEditor()->GetHeightmap()->UpdateEngineTerrain( true );

	// All layers need to be generated from scratch
	GetIEditor()->GetHeightmap()->InvalidateLayers();

	if (GetTerrainTool())
	{
		CTerrainBrush br;
		GetTerrainTool()->GetCurBrushParams(br);
		if (br.bRepositionObjects)
		{
			AABB box;
			box.min = -Vec3(100000,100000,100000);
			box.max = Vec3(100000,100000,100000);
			if (GetIEditor()->GetVegetationMap())
				GetIEditor()->GetVegetationMap()->RepositionArea( box );
			// Make sure objects preserve height.
			GetIEditor()->GetObjectManager()->SendEvent( EVENT_KEEP_HEIGHT,box );
		}
	}

	GetIEditor()->GetGameEngine()->ReloadEnvironment();

	InvalidateViewport();
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::InvalidateViewport()
{
	m_pViewport->Invalidate();
	GetIEditor()->UpdateViews(eUpdateHeightmap);
}


//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::OnEditorNotifyEvent( EEditorNotifyEvent event )
{
	switch (event)
	{
	case eNotify_OnEndNewScene:
	case eNotify_OnEndSceneOpen:
	case eNotify_OnTerrainRebuild:
		m_pViewport->InitHeightmapAlignment();
		InvalidateViewport();
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::OnCustomize()
{
	CMFCUtils::ShowShortcutsCustomizeDlg(GetCommandBars(), IDR_TERRAIN, "TerrainEditor");
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::OnExportShortcuts()
{
	CMFCUtils::ExportShortcuts(GetCommandBars()->GetShortcutManager());
}

//////////////////////////////////////////////////////////////////////////
void CTerrainDialog::OnImportShortcuts()
{
	CMFCUtils::ImportShortcuts(GetCommandBars()->GetShortcutManager(), "TerrainEditor");
}
